#include <iostream>
#include <string>
#include <memory> //智能指针
#include <vector>
#include <map>
#include "smart-pointer-impl.hpp"

#ifdef USESTD
    #define SPNS std //namesapce of smart pointer
#else
    #define SPNS mytmpl
#endif //USESTD 

using std::cout;
using std::endl;

class B;  
class A{  
    public:  
        SPNS::shared_ptr<B> ptr_A;  
        ~A(){  
            cout << "refcount " << ptr_A.use_count() << '\n';
            cout<<"~A()"<<endl;  
        }  
};  
class B{  
    public:  
#ifdef USEWEAKPTR
        SPNS::weak_ptr<A> ptr_B;//当采用弱引用时，避免了循环引用，有输出，说明对象被析构了  
#else
        //当采用shared_ptr指向A时会形成循环引用，则什么都不会输出说明对象没有被
        //析构，可怕的内存泄露....  
        SPNS::shared_ptr<A> ptr_B;
#endif //USEWEAKPTR
        ~B(){  
            cout << "refcount " << ptr_B.use_count() << '\n';
            cout<<"~B()"<<endl;  
        }  
};

//unique_ptr
void mytest1() {
    SPNS::unique_ptr<int> up1(new int(11));   // 无法复制的unique_ptr
    //unique_ptr<int> up2 = up1;        // err, 不能通过编译
    std::cout << *up1 << std::endl;   // 11

    SPNS::unique_ptr<int> up3 = std::move(up1);    // 现在p3是数据的唯一的unique_ptr

    std::cout << *up3 << std::endl;   // 11
    //std::cout << *up1 << std::endl;   // err, 运行时错误
    up3.reset();            // 显式释放内存
    up1.reset();            // 不会导致运行时错误
    //std::cout << *up3 << std::endl;   // err, 运行时错误

    SPNS::unique_ptr<int> up4(new int(22));   // 无法复制的unique_ptr
    up4.reset(new int(44)); //"绑定"动态对象
    std::cout << *up4 << std::endl; // 44

    up4 = nullptr;//显式销毁所指对象，同时智能指针变为空指针。与up4.reset()等价

    SPNS::unique_ptr<int> up5(new int(55));
    int *p = up5.release(); //只是释放控制权，不会释放内存
    std::cout << *p << std::endl;
    //cout << *up5 << endl; // err, 运行时错误
    delete p; //释放堆区资源

    return;
}

//shared_ptr
void mytest2() {
    SPNS::shared_ptr<int> sp1(new int(22));
    SPNS::shared_ptr<int> sp2 = sp1;
    std::cout << "cout: " << sp2.use_count() << std::endl; // 打印引用计数

    std::cout << *sp1 << std::endl;
    std::cout << *sp2 << std::endl;

    sp1.reset(); // 显示让引用计数减一
    std::cout << "count: " << sp2.use_count() << std::endl; // 打印引用计数

    std::cout << *sp2 << std::endl; // 22

    return;
}

//weak_ptr
void check(SPNS::weak_ptr<int> &wp) {
    SPNS::shared_ptr<int> sp = wp.lock(); // 转换为shared_ptr<int>
    if (sp != nullptr)
    {
        std::cout << "still: " << *sp << std::endl;
    } 
    else
    {
        std::cout << "still: " << "pointer is invalid" << std::endl;
    }
}

//weak_ptr
void mytest3() {
    SPNS::shared_ptr<int> sp1(new int(22));
    SPNS::shared_ptr<int> sp2 = sp1;
    SPNS::weak_ptr<int> wp = sp1; // 指向shared_ptr<int>所指对象

    std::cout << "count: " << wp.use_count() << std::endl; // count: 2
    std::cout << *sp1 << std::endl; // 22
    std::cout << *sp2 << std::endl; // 22
    check(wp); // still: 22
    
    sp1.reset();
    std::cout << "count: " << wp.use_count() << std::endl; // count: 1
    std::cout << *sp2 << std::endl; // 22
    check(wp); // still: 22

    sp2.reset();
    std::cout << "count: " << wp.use_count() << std::endl; // count: 0
    check(wp); // still: pointer is invalid

    return;
}


//自定义释放规则, 区分单个对象和数组
void deleteInt(int*p) {
    delete []p;
}

//混合测试
void mytestMix() {
    SPNS::shared_ptr<int> p1;
    SPNS::shared_ptr<int> p2(nullptr);
    SPNS::shared_ptr<int> p3(new int(10));
#ifdef USESTD
    p3 = std::make_shared<int>(10);
#else 
    p3 = mytmpl::shared_ptr<int>(new int(10));
#endif //USESTD
    SPNS::shared_ptr<int> p4(p3); //拷贝构造函数
    p4 = p3; //opertaor=重载函数
    SPNS::shared_ptr<int> p5(std::move(p4)); //移动
    int *ptr = new int;
    p1 = SPNS::shared_ptr<int>(ptr);
    //p2 = shared_ptr<int>(ptr); #error
    //指定释放规则
    SPNS::shared_ptr<int> p6(new int[10], std::default_delete<int[]>());
    //初始化智能指针，并指定自定义释放规则
    SPNS::shared_ptr<int> p7(new int[10], deleteInt);
    //借助 lambda 表达式初始化/赋值p7
    p7 = SPNS::shared_ptr<int>(new int[10], [](int* p) {delete[]p; });
    
    //构建 2 个智能指针
    SPNS::shared_ptr<int> p11(new int(10));
    SPNS::shared_ptr<int> p21(p11);
    //输出 p2 指向的数据
    cout << *p21 << endl;
    p11.reset();//引用计数减1, p11为空指针
    if (p11) {
        cout << "p11 不为空" << endl;
    }
    else {
        cout << "p11 为空" << endl;
    }
    //以上操作，并不会影响 p21
    cout << *p21 << endl;
    //判断当前和 p21 同指向的智能指针有多少个
    cout << p21.use_count() << endl;

    
    SPNS::unique_ptr<int> p41(new int);
    //SPNS::unique_ptr<int> p51(p41);//错误，堆内存不共享    
    
    //正确，调用移动构造函数, p41变为空
    SPNS::unique_ptr<int> p51(std::move(p41));
    
    //自定义的释放规则
    struct myDel {
        void operator()(int *p) {
            delete p;
        }
    };
    SPNS::unique_ptr<int, myDel> p61(new int);
    SPNS::unique_ptr<int, myDel> p62(new int, myDel());
    
    SPNS::unique_ptr<int> p52(new int);
    *p52 = 10;
    // p 接收 p52 释放的堆内存
    int *p = p52.release();
    cout << *p << endl;
    //判断 p52 是否为空指针
    if (p52) {
        cout << "p52 is not nullptr" << endl;
    }
    else {
        cout << "p52 is nullptr" << endl;
    }
    SPNS::unique_ptr<int> p63;
    //p63 获取 p 的所有权
    p63.reset(p);
    cout << *p63 << endl;;
    
}
//循环引用测试
void ref_circle_test() {
    SPNS::shared_ptr<A> a(new A);  
    SPNS::shared_ptr<B> b(new B);  
    a->ptr_A=b;  
    b->ptr_B=a;//若是循环引用：当a、b退出作用域的时候，A对象计数不为1(b保留了个计数呢),同理B的计数也不为1,那么对象将不会被销毁，内存泄露了... 
    cout << a.use_count() << " "  << b.use_count()<< endl;
}

int main() {
    cout << "Starting test!!!" << endl;
    mytest1();
    cout << "Test flag1!!!" << endl;
    mytest2();
    cout << "Test flag2!!!" << endl;
    mytest3();
    cout << "Test flag3!!!" << endl;
    mytestMix();
    cout << "Test flag4!!!" << endl;
    ref_circle_test();
    cout << "Test finished!!!" << endl;
    return 0;
}
